package com.wymobilearchitecture.demo.kt



/**
 * lambda
 * 底层实现本质为匿名方法
 *
 * 无参数的情况
 * val/var 变量名 = { 操作的代码 }
 *
 * 有参数的情况
 * val/var 变量名 : (参数的类型,参数的类型,...) -> 返回值类型 = {参数1,参数2,... -> 操作参数的代码 }
 * 可等价于
 * 此种写法:即表达式的返回值类型会根据操作的代码自推导出来
 * val/var 变量名 = { 参数1 : 类型,参数2 : 类型,... -> 操作参数的代码 }
 *
 * lambda 表达式作为方法中的参数的时候,这里举一个例子
 * fun test(a : Int,参数名 : (参数1 : 类型,参数2 : 类型,...) -> 表达式返回
 * */


fun main(){

    test()
    test1()

    println(test2(2,3))
    println(test3(4,5))

    test5()
    test6()

    //高阶函数-函数作为参数
    val list : List<Int> = listOf(1,2,3,4,5)
    println("高阶函数-参数: ${list.sum { println("list值: $it") }}" )

    //高阶函数-函数作为返回值
    val listString : List<String> = listOf("1","2","3","4","5")
    val resultString = listString.toIntSum()(2)
    println("高阶函数-返回值: $resultString")

    //闭包
    testClosure(2)(3){
        println("闭包: $it")
    }

    /**
     *
     */
    val funAdd = add()
    funAdd()
    funAdd()
    funAdd()


    //解构
    test7()

    //方法字面值
    literal()



}

/**
 * 普通方法,无参数情况
 */
fun test(){
    println("无参数")
}
/**
 * lambda 写法
 */
val test1 = { println("无参数")}


/**
 * 普通方法,有参数
 */
fun test2(a : Int ,b : Int) : Int{
    return a + b
}

/**
 * lambda 写法
 */
val test3 : (Int,Int) -> Int = {a,b -> a + b}//声明带类型写法
val test4 = {a : Int,b : Int -> a + b} // 声明不带类型写法


/**
 * it 用法,不是关键字,当高阶方法中 lambda 表达式的参数只有一个的时候可以使用 it 来使用该参数
 */
fun test5(){
    val array = arrayOf(1,2,3,4)
    println("it用法: ${array.filter { it < 4 }}")
}


/**
 * 可以使用下划线代替掉不使用的参数
 */

fun test6(){
    val map = mapOf<String,Int>("a" to 1,"b" to 2,"c" to 3,"d" to 4)
//    map.forEach { (k, v) -> println(k)}
    map.forEach { (k, _) -> println(k)}
}


/**
 * 高阶函数-函数作为参数
 * 对集合元素进行求和,并且每遍历一个元素都要回调
 * callback 方法名;() 代表方法, (Int) 方法的参数; Unit 返回值
 * */
fun List<Int>.sum(callback : (Int) -> Unit) : Int{

    var result : Int = 0;
    for (item in this) {
        result += item
        callback(item)
    }

    return result
}



/**
 * 高阶函数-函数作为返回值
 * 对集合元素进行求和,并且返回一个声明为 (scale : Int) -> Float 的函数  scale:缩放倍率
 * */
fun List<String>.toIntSum() :(scale : Int) -> Float{
    println("第一层函数")
    return fun (_scale : Int) : Float{
        var result = 0f
        for (v in this){
            result += v.toInt() * _scale
        }
        return result
    }
}

/**
 * 闭包
 * 概念: 可以理解为能够读取其他方法内部变量的方法
 *      是将方法内部和方法外部链接起来的桥梁
 * 特性: 可以作为另一个方法的返回值和参数,还可以作为一个变量的值
 *       方法可以嵌套定义,即再一个方法内部可以定义另一个方法
 * 好处: 加强模块化,抽象,灵活,简化代码
 * */
fun testClosure(v1 : Int) : (v2 : Int,fun2 :(Int) -> Unit) -> Unit{
    //返回值类型要一致
    return fun(v2 : Int,printer : (Int) -> Unit){
        printer(v1 + v2)
    }
}

/**
 * 普通函数不携带状态,调用完里面内容会被释放掉,下次调用的时候变量会再次声明
 */
fun addTest(){
    var count = 0;
    println(count)
}

/**
 * 函数不携带状态,维护起来就需要额外的成本,比如我们需要额外的声明一个变量来记录它的状态,闭包可以让函数携带状态
 *
 * 函数里面声明函数,函数里面返回函数,就是闭包,函数内部的局部变量的状态保存住了(变量的值就是状态),
 * 局部变量的值被隐藏起来了,但是我们调用函数可以改变状态,或者获得局部变量的值,这点就是函数的面向对象,让函数具有封装的能力,让函数有了状态
 */
fun add():() -> Unit{
    var count = 0
    return fun (){
        println(count++)
    }
}

//T.run()是作为泛型T的一个扩展函数，所以在传入的lambda表达式中可以使用this关键字来访问这个泛型T中的成员变量和成员方法。
//public inline fun <T, R> T.run(block: T.() -> R): R {
//    contract {
//        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
//    }
//    return block()
//}




/**
 * 解构
 */
data class Result(var message: String,var code:Int)
fun test7(){
    val resultBean : Result = Result("mmmssss",230)
    var(message,code) = resultBean
    println("解构: $message , $code")
}

/***
 * 匿名方法
 */
val fun1 = fun(x : Int,y : Int) : Int{
    return x + y
}

/**
 * 方法字面值
 */
fun literal(){
//   定义一个变量 tmp,该变量的类型就是 (Int) -> Boolean
    var temp : ((Int) -> Boolean)? = null
    //{num -> (num > 10)} 与上面类型对应,这段就是,方法字面值
    temp = {num -> (num > 10)}
    println("方法字面值: ${temp(11)}")
}



